package com.lucy.disk.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.crypto.SecureUtil;
import com.lucy.common.constant.HttpStatus;
import com.lucy.common.domain.ResponseDTO;
import com.lucy.disk.domain.entity.FileEntity;
import com.lucy.disk.domain.model.BaseFile;
import com.lucy.disk.event.FileDeletedEvent;
import com.lucy.disk.minio.utils.MinioUtil;
import com.lucy.disk.params.FileCreateParams;
import com.lucy.disk.params.FileQueryParams;
import com.lucy.disk.params.FileUpdateParams;
import com.lucy.disk.service.FileService;
import com.lucy.disk.utils.DiskUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kindear
 * 文件管理控制器
 */

@Slf4j
@RestController
@RequestMapping("disk")
@Api(tags = "文件管理")
public class DiskFileController {
    @Autowired
    FileService fileService;

    @Autowired
    MinioUtil minioUtil;

    @Resource
    ApplicationContext context;

    @PostMapping("file")
    @ApiOperation(value = "文件创建",notes = "文件(夹)创建")
    public ResponseDTO<Object> fileCreate(@RequestBody @Validated FileCreateParams params){
        String fileName = params.getFileName();
        String extName = FileNameUtil.extName(fileName);
        // 获取当前登录用户
        String userId = StpUtil.getLoginIdAsString();
        if (Validator.isEmpty(extName)){
            // 无后缀名 新建目录
            return ResponseDTO.succData(
                    fileService.createDir(params.getDirId(), fileName, userId)
            );

        }else {
            // 有后缀名 新建文件
            return ResponseDTO.succData(
                    fileService.createFile(params.getDirId(), fileName, userId)
            );
        }
    }

    @DeleteMapping("file/{fileId}")
    @ApiOperation(value = "文件删除",notes = "")
    public ResponseDTO<Object> fileDelete(@PathVariable("fileId") String fileId){
        String loginId = StpUtil.getLoginIdAsString();
        FileEntity fileEntity = new FileEntity();
        fileEntity.setUserId(loginId);
        Example<FileEntity> example = Example.of(fileEntity);
        List<FileEntity> files = fileService.getExample(example);
        List<Tree<String>> nodeList  = fileTreeBuild(files,fileId);
        List<String> deleteIds = getAllChild(nodeList);
        deleteIds.add(fileId);
        fileService.batchDelete(deleteIds);
        // 遍历 -- 事件发布 -- 异步
        for (FileEntity file:files){
            for (String id:deleteIds){{
                if (id.equals(file.getId())){
                    context.publishEvent(new FileDeletedEvent(this,file));
                }
            }}
        }

        return ResponseDTO.succMsg("删除成功");
    }

    @PutMapping("file")
    @ApiOperation(value = "文件修改",notes = "")
    public ResponseDTO<Object> fileUpdate(@RequestBody @Validated FileUpdateParams params){
        String fileId = params.getId();
        Optional<FileEntity> fileOp = fileService.getOne(fileId);
        if (!fileOp.isPresent()){
            return ResponseDTO.wrap(
                    HttpStatus.NOT_FOUND,
                    "ID对应文件信息不存在"
            );
        }
        FileEntity file = fileOp.get();
        BeanUtil.copyProperties(params,file,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        return ResponseDTO.succData(
                fileService.updateOne(file)
        );
    }

    /**
     * 构建选择树 原始方法
     * @param files
     * @param rootId
     * @return
     */
    public List<Tree<String>> fileTreeBuild(List<FileEntity> files,String rootId){
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setWeightKey("isDir");
        treeNodeConfig.setParentIdKey("dirId");
        return TreeUtil.build(files, rootId, treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getDirId());
                    tree.setWeight(treeNode.getIsDir());
                    tree.setName(treeNode.getFileName());
                    // 是否为文件夹
                    tree.putExtra("isDir",treeNode.getIsDir());
                });
    }

    /**
     * 获取全部后代节点
     * @param nodeList
     * @return
     */
    public List<String> getAllChild(List<Tree<String>> nodeList){
        if (Validator.isEmpty(nodeList)){
            return new ArrayList<>();
        }
        Set<String> resSet = new HashSet<>();
        nodeList.forEach(stringTree -> {
            resSet.add(stringTree.getId());
            if (Validator.isNotEmpty(stringTree.getChildren()) && stringTree.getChildren().size() != 0){
                resSet.addAll(getAllChild(stringTree.getChildren()));
            }
        });
        return new ArrayList<>(resSet);
    }

    @GetMapping("file/tree")
    @ApiOperation(value = "文件树构建",notes = "")
    public ResponseDTO<Object> fileTreeBuild(
            @RequestParam(value = "fileId",required = false) String fileId,
            @RequestParam(value = "isDir",required = false) Integer isDir
    ){
        String loginId = StpUtil.getLoginIdAsString();
        FileEntity fileEntity = new FileEntity();
        fileEntity.setUserId(loginId);
        // 如果限制为目录--加入限制条件
        if (isDir.equals(1)){
            fileEntity.setIsDir(isDir);
        }

        Example<FileEntity> example = Example.of(fileEntity);
        List<FileEntity> files = fileService.getExample(example);
        // rootId 配置
        String rootId = "";
        if (Validator.isNotEmpty(fileId)){
            rootId = fileId;
        }
        return ResponseDTO.succData(
                fileTreeBuild(files,rootId)
        );
    }


    @GetMapping("file/{fileId}")
    @ApiOperation(value = "文件查询",notes = "")
    public ResponseDTO<Object> fileQuery(@PathVariable("fileId") String fileId){
        Optional<FileEntity> fileOp = fileService.getOne(fileId);

        return fileOp.<ResponseDTO<Object>>map(ResponseDTO::succData).orElseGet(() -> ResponseDTO.wrap(
                HttpStatus.NOT_FOUND,
                "ID对应文件信息不存在"
        ));
    }



    @GetMapping("file")
    @ApiOperation(value = "文件列表",notes = "")
    public ResponseDTO<Object> fileQueryList(FileQueryParams params){
        Sort sort;
        if("DESC".equalsIgnoreCase(params.getOrder())){
            sort = Sort.by(Sort.Direction.DESC, params.getSortBy());
        }else {
            sort = Sort.by(Sort.Direction.ASC, params.getSortBy());
        }

        // tips : 页码对应 - 1
        Pageable pageable = PageRequest.of(params.getPageNum() - 1 , params.getPageSize(), sort);
        /*
        构建 Example
         */
        FileEntity fileEntity = new FileEntity();
        BeanUtil.copyProperties(params,fileEntity, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        Example<FileEntity> example = Example.of(fileEntity);
        return ResponseDTO.succData(fileService.getAll(pageable,example));
    }

}
